﻿/// <reference path="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2-vsdoc.js"/>
/// <reference path="slider.js" />
/// <reference path="ajaxupdatepanel.js" />
/// <reference path="wayfinder.js" />
/*globals $,jQuery*/

var Microsoft = window.Microsoft || {};
Microsoft.Support = Microsoft.Support || {};
Microsoft.Support.GSS = Microsoft.Support.GSS || {};

Microsoft.Support.GSS.GPS = function (container, args) {
    // using
    var ScopeNodeType = Microsoft.Support.GSS.ScopeNodeType;
    var ScopeNode = Microsoft.Support.GSS.ScopeNode;

    var _this = this;
    var _$this = $(this);
    var _$container = $(container);
    var _defaultOptions = {
        language: 'en-us',
        isRTL: false,
        loadingHtml: '<h3>Loading...</h3>',
        errorHtml: '<h3>Error!</h3>',
        modality: '',
        scope: null,
        query: '',
        gpsServiceUrl: '/GuidedProblemSolving/GuidedProblemSolvingService.svc',
        modalitySettings: {
            "": {
                allowCache: function (modality, scope, query) {
                    return false;
                },
                forceLoad: function (modality, scope, query) {
                    return false;
                },
                getContentKey: function (modality, scope, query) {
                    return Array.prototype.slice.call(arguments).join("_");
                }
            }
        }
    };
    var _opts = $.extend(true, {}, _defaultOptions, args);
    var _cachedContents = {};
    var _lts = new Microsoft.Support.GSS.GPS.LTS(window.StatsDotNet, {
        scope: _opts.scope
    });

    var _slider = new Microsoft.Support.GSS.Slider(container, {
        easingEffect: 'easeOutExpo',
        isRTL: _opts.isRTL
    });

    var _trimAndLowerCase = function (str) {
        return str ? $.trim(str.toString()).toLowerCase() : '';
    };

    var _parseQueryString = function (query) {
        var queryMap = {};
        if ($.isPlainObject(query)) return query;
        query = $.trim(query);
        query = query.substr(query.indexOf("?") + 1);
        if (query) {
            $.each(query.split('&'), function (idx, item) {
                var parts = item.split('=');
                var key = decodeURIComponent(parts[0]);
                var val = decodeURIComponent(parts[1]);
                if (key) {
                    if (key.substr(key.length - 2) === '[]') {
                        key = key.substr(0, key.length - 2);
                        if (!$.isArray(queryMap[key])) {
                            queryMap[key] = [];
                        }
                        queryMap[key].push(val);
                    } else {
                        queryMap[key] = val;
                    }
                }
            });
        }
        return queryMap;
    };

    var _getModailitySettings = function (modality) {
        return $.extend({}, _opts.modalitySettings[""], _opts.modalitySettings[modality]);
    };

    var _allowCache = function (modality, scope, query) {
        var settings = _getModailitySettings(modality);
        return ($.isFunction(settings.allowCache) ?
                settings.allowCache(modality, scope, query) : settings.allowCache) ? true : false;
    };

    var _forceLoad = function (modality, scope, query) {
        var settings = _getModailitySettings(modality);
        return ($.isFunction(settings.forceLoad) ?
                settings.forceLoad(modality, scope, query) : settings.forceLoad) ? true : false;
    };

    var _getContentKey = function (modality, scope, query) {
        var settings = _getModailitySettings(modality);
        return $.isFunction(settings.getContentKey) ?
                (settings.getContentKey(modality, scope, query)) :
                (typeof settings.getContentKey === 'string' ?
                        settings.getContentKey : [modality, scope, query].join("_"));
    };

    var _getCurrPage = function () {
        return _slider.getPage();
    };

    var _setPageData = function (page, modality, scope, query) {
        $(page || _getCurrPage()).data("gps-modality", modality).data("gps-scope", scope)
            .data("gps-query", query).data("gps-key", _getContentKey(modality, scope, query));
        return page;
    };

    var _getPageData = function (page) {
        page = $(page || _getCurrPage());
        return {
            key: page.data("gps-key"),
            modality: page.data("gps-modality"),
            scope: page.data("gps-scope"),
            query: page.data("gps-query")
        };
    };

    var _loadModalityContent = function (modality, scope, query) {
        var $panel = $("<div></div>");
        var $loadingPanel = $("<div class='loading-panel'></div>").appendTo($panel).html(_opts.loadingHtml);
        var $errorPanel = $("<div class='error-panel'></div>").appendTo($panel).html(_opts.errorHtml);

        var panel = $panel[0];
        var instance = new Microsoft.Support.GSS.AjaxUpdatePanel($panel, {
            loadingPanelDelayTime: 500,
            loadingPanelSelector: $loadingPanel,
            errorPanelSelector: $errorPanel,
            ajaxSettings: {
                cache: false,
                dataType: 'json',
                url: _opts.gpsServiceUrl + "/GetGPSPageContent",
                data: {
                    lang: _opts.language,
                    modalityType: modality,
                    path: scope ? scope.getPath() : "",
                    query: $.param(query),
                    ccsid: (new Date().valueOf() * 10000) + Math.random() * 10000
                }
            }
        });
        panel._instance = instance;
        instance.load();
        $errorPanel.find(".retry-link").click(function (e) {
            e.preventDefault();
            instance.load();
        });
        return _setPageData(panel, modality, scope, query);
    };

    var _init = function () {
        $.each(_opts.modalitySettings, function (key, val) {
            var newKey = _trimAndLowerCase(key);
            if (newKey !== key) {
                _opts.modalitySettings[newKey] = val;
            }
        });

        var currPage = _getCurrPage();
        _setPageData(currPage,
            _trimAndLowerCase(_opts.modality),
            _opts.scope,
            _parseQueryString(_opts.query));
        var data = _getPageData(currPage);
        if (_allowCache(data.modality, data.scope, data.query)) {
            _cachedContents[data.key] = currPage;
        }

        // handle get-instances event
        $(document).on("get-instances", function (e, instances, matchFunc) {
            matchFunc = $.isFunction(matchFunc) ? matchFunc : $.isFunction(instances) ? instances : null;
            instances = $.isArray(instances) ? instances : [];
            if (matchFunc === null || matchFunc(_this) === true) {
                instances.push(_this);
            }
        });

        // lts logging init
        $(document).on("click", "[data-gps-lts-log]", function (e) {
            var cfg = $(this).data("gps-lts-log");
            if (typeof cfg === 'string') {
                try {
                    cfg = $.parseJSON($(this).data("gps-lts-log"));
                } catch (ex) { }
            }
            if ($.isPlainObject(cfg)) {
                $.each(cfg, function (selector, eventType) {
                    var target = $(e.target).closest(selector);
                    if (target[0]) {
                        var data = _getPageData();
                        var scope = target.data("node");
                        _lts.log(eventType, data.modality, scope instanceof ScopeNode ? scope : data.scope, data.query, null, e);
                    }
                });
            }
        });

        // trigger GPSInitStatus log
        $(function () {
            var gpsInitData = {};
            $(document).trigger("get-instances", [function (instance) {
                if (instance instanceof Microsoft.Support.GSS.GPS.Hero) {
                    $.each(instance.getStatus(), function (key, val) {
                        gpsInitData["hero_" + key] = val;
                    });
                }
            } ]);
            _lts.log("GPSInitStatus", data.modality, data.scope, data.query, gpsInitData);
        });
    };

    _init();

    _this.changeModality = function (modality, scope, query) {
        modality = _trimAndLowerCase(modality);
        query = _parseQueryString(query);
        var key = _getContentKey(modality, scope, query);
        var forceLoad = _forceLoad(modality, scope, query);
        var currPage = _getCurrPage();
        var page = currPage;
        if (_getPageData(page).key !== key || forceLoad) {
            page = forceLoad ? null : _cachedContents[key];
            if (!page) {
                page = _loadModalityContent(modality, scope, query);
                if (_allowCache(modality, scope, query)) {
                    _cachedContents[key] = page;
                }
            }
        }

        _setPageData(page, modality, scope, query);
        if (currPage !== page) {
            _slider.replacePage(0, page, function (removedPage) {
                //$(page).focus();      // fixes bug 328437
                var cached = false;
                $.each(_cachedContents, function (key, p) {
                    if (p === removedPage) {
                        cached = true;
                        return false;
                    }
                });

                if (cached) {
                    _slider.insertPage(removedPage);
                } else {
                    $(removedPage).remove();
                }
            }, true);

            _$this.trigger("pagechange", [page, _getPageData(page)]);
        }
    };

    _this.changeScope = function (scope, query) {
        _this.changeModality(_getPageData().modality, scope, query);
    };

    _this.changeQuery = function (query) {
        var data = _getPageData();
        query = _parseQueryString(query);
        _this.changeModality(data.modality, data.scope, query);
        if (query.query !== undefined) {
            _lts.log("Search", data.modality, data.scope, query.query);
        }
    };
};

Microsoft.Support.GSS.GPS.Hero = function (selector, args) {
    // using
    var ScopeNodeType = Microsoft.Support.GSS.ScopeNodeType;
    var ScopeNode = Microsoft.Support.GSS.ScopeNode;

    var _this = this;
    var _$container = $(selector);
    var _defaultOptions = {
        language: 'en-us',
        isRTL: false,
        pagesSelector: $(".hero", _$container),
        modality: '',
        scope: null
    };
    var _opts = $.extend({}, _defaultOptions, args);
    var _slider = null;
    var _$pages = $();

    var _getHeroPageIndex = function (page) {
        var i;
        for (i = 0; i < _$pages.length; i++) {
            if ($(_$pages.get(i)).attr("id") === "hero_" + page) {
                return i;
            }
        }

        return 0;
    };

    var _getStatus = function () {
        var page = _slider.getPage();
        return {
            visible: _$container.is(":visible"),
            image: $("img", page).attr("src"),
            text: $.trim($(page).text())
        };
    };

    var _init = function () {
        var currPageIndex = 0;
        _$pages = $(_opts.pagesSelector).show();

        if (typeof _opts.modality === 'string' && _opts.modality) {
            currPageIndex = _getHeroPageIndex(_opts.modality.toLowerCase());
        }

        _slider = new Microsoft.Support.GSS.Slider(_$container, {
            easingEffect: 'easeOutExpo',
            initPageIndex: currPageIndex,
            pagesSelector: _$pages,
            isRTL: _opts.isRTL
        });
        if (typeof _opts.modality === 'string' && _opts.scope && _opts.scope.getPath()) {
            _$container.hide();
        }

        // handle get-instances event
        $(document).on("get-instances", function (e, instances, matchFunc) {
            matchFunc = $.isFunction(matchFunc) ? matchFunc : $.isFunction(instances) ? instances : null;
            instances = $.isArray(instances) ? instances : [];
            if (matchFunc === null || matchFunc(_this) === true) {
                instances.push(_this);
            }
        });
    };
    _init();

    _this.getStatus = function () {
        return _getStatus();
    };

    this.switchPage = function (modality, scope) {
        if (scope && scope.findChildrenByType(ScopeNodeType.Product).length === 0) {
            _$container.slideUp('slow', null);
            return;
        }

        if (typeof modality === 'string') {
            var pageIndex = _getHeroPageIndex(modality.toLowerCase());
            _slider.gotoPage(pageIndex);
        }
    };
};

Microsoft.Support.GSS.GPS.TopicControl = function (selector, args) {
    // using
    var ScopeNodeType = Microsoft.Support.GSS.ScopeNodeType;
    var ScopeNode = Microsoft.Support.GSS.ScopeNode;

    var _this = this;
    var _$this = $(this);
    var _$ctrlCt = $(selector);
    var _defaultOptions = {
        serviceUrl: '/GuidedProblemSolving/GuidedProblemSolvingService.svc',
        language: 'en-us',
        isRTL: false,
        modality: 'SelfHelp',
        productNode: null,
        ajaxSettings: {
            cache: false,
            dataType: 'json'
        }
    };
    var _opts = $.extend(true, {}, _defaultOptions, args);
    var _$topicLv1Panel = $();
    var _$topicLv2Panel = _$topicLv1Panel;
    var _topicLv2Slider = null;
    var _topicLv2Panel = null;
    var _curProductNode = null;
    var _curScopeNode = null;

    var _getTopicNode = function ($item) {
        var node = $item.data("node");
        if (node instanceof ScopeNode) {
            return node;
        }

        var leaf = parseInt($item.data("leaf"), 10) > 0;
        node = new ScopeNode(
            ScopeNodeType.Topic,
            $item.data("key"),
            $.trim($item.find("> a").text()),
            {
                id: parseInt($item.data('id'), 10),
                leaf: leaf
            },
            leaf ? [] : null
        );
        $item.data("node", node);
        return node;
    };

    var _getScopePath = function (linkElem) {
        var $linkElem = $(linkElem);
        var path = $linkElem.data("path");
        if (path) {
            return path;
        }

        path = $.trim($linkElem.attr("href"));
        if (path[0] === '/') { path = path.substr(1); }
        if (path[path.length - 1] === '/') { path = path.substr(0, path.length - 1); }
        var pathParts = path.split('/');
        pathParts.splice(0, 1);
        return pathParts.join('/');
    };

    var _getProductScopePath = function () {
        var path = _getScopePath(_$topicLv1Panel.find("li:first a"));
        return path.substr(0, path.lastIndexOf('/'));
    };

    var _changeTopic = function (link) {
        var $link = $(link);
        var node = $link.parent("li").data("node");
        node = node || _curProductNode;

        if (_curScopeNode !== node) {
            _curScopeNode = node;
            _$this.trigger("scopechange", node);
        }
    };

    var _initTopicListLv2 = function (panel) {
        var $items = $(panel || _$topicLv2Panel).find("li.sub-topic-item");

        if (_curScopeNode.get("type") === ScopeNodeType.Topic) {
            _curScopeNode.clearChildren();
            $items.each(function () {
                var $item = $(this);
                var topicNode = _getTopicNode($item);
                _curScopeNode.addChildren(topicNode);
            });

            var $selected = $items.filter(".selected:first");
            if ($selected.length > 0) {
                _curScopeNode = $selected.data("node");
            }
        }

        $("a", $items).click(function (e) {
            var $this = $(this);
            e.preventDefault();
            $this.parent("li").addClass("selected").siblings().removeClass("selected");
            _changeTopic($this);
        });
    };

    var _init = function () {
        _$topicLv1Panel = $(".topic-list-lv1", _$ctrlCt);
        _$topicLv2Panel = $(".topic-list-lv2", _$ctrlCt);

        var selectedLv1Link = _$topicLv1Panel.find("li.selected a");
        var selectedLv2Link = selectedLv1Link[0] ? _$topicLv2Panel.find("li.selected a") : null;

        // init current scope
        if (_opts.productNode instanceof ScopeNode) {
            _curProductNode = _opts.productNode;
        } else {
            // make fake product node
            var productNode = null;
            $.each(ScopeNode.prototype.parsePath($.trim(_$ctrlCt.data("product-path"))), function (idx, productKey) {
                if (productKey) {
                    var node = new ScopeNode(ScopeNodeType.Product, productKey);
                    if (productNode) {
                        node.setParent(productNode);
                    }
                    productNode = node;
                }
            });
            _curProductNode = productNode || new ScopeNode(ScopeNodeType.Root);
            _curProductNode._props.seamId = _$ctrlCt.data("product-seam-id");    //TODO: hack to modify props, not good pratice!
        }
        _curScopeNode = _curProductNode;

        // build topic lv1 nodes structure
        var curTopicNode = _$topicLv1Panel.find("li.topic-item").each(function () {
            var $item = $(this);
            var topicNode = _getTopicNode($item);
            _curProductNode.addChildren(topicNode);
        }).filter(".selected:first").data("node");
        if (curTopicNode) {
            _curScopeNode = curTopicNode;
        }

        $("script[type='text/html']", _$topicLv2Panel).each(function () {
            var $this = $(this);
            $this.after($this.html()).remove();
        });

        _topicLv2Slider = new Microsoft.Support.GSS.Slider(_$topicLv2Panel, {
            easingEffect: 'easeOutExpo',
            isRTL: _opts.isRTL
        });

        _topicLv2Panel = new Microsoft.Support.GSS.AjaxUpdatePanel(_$topicLv2Panel.find(".wrapper"), {
            loaded: true,
            ajaxSettings: $.extend(true, {}, _opts.ajaxSettings, {
                url: _opts.serviceUrl + "/GetSubtopicList",
                data: { lang: _opts.language }
            })
        });
        _$topicLv2Panel.on("click", ".retry-link", null, function (e) {
            e.preventDefault();
            if (_topicLv2Panel) {
                _topicLv2Panel.load();
            }
        });

        _$topicLv1Panel.find("li a").click(function (e) {
            var $this = $(this);
            e.preventDefault();     // prevent default click event
            $this.parent("li").addClass("selected").siblings().removeClass("selected");
            _changeTopic($this);

            // load topic lv2
            var $newTopicLv2Ct = _topicLv2Panel.cloneEmptyContainer();
            if (_curScopeNode.get("props").leaf) {  // no topic lv2
                _topicLv2Slider.replacePage(0, $newTopicLv2Ct[0]);
            } else {
                _topicLv2Panel = new Microsoft.Support.GSS.AjaxUpdatePanel($newTopicLv2Ct, {
                    loaded: false,
                    ajaxSettings: $.extend(true, {}, _opts.ajaxSettings, {
                        url: _opts.serviceUrl + "/GetSubtopicList",
                        data: { lang: _opts.language }
                    })
                });
                var loadTopicId = _curScopeNode.get("props").id;
                $(_topicLv2Panel).bind("beforeload", function (e, settings) {
                    settings.data.modalityType = _opts.modality;
                    settings.data.productId = _curScopeNode.findParentByType(ScopeNodeType.Product).get("props").seamId;
                    settings.data.topicId = loadTopicId;
                }).bind("load", function (e, panel) {
                    _initTopicListLv2(panel);
                }).bind("complete", function () {
                    // in case of switching to another topic while toplic lv2 isn't loaded yet.
                    if (_curScopeNode.get("props").id === loadTopicId) {
                        _topicLv2Slider.replacePage(0, $newTopicLv2Ct[0], function () {
                            //$newTopicLv2Ct.focus(); // fixes bug 328437
                        });
                    }
                });
                _topicLv2Panel.load();
            }
        });

        _$ctrlCt.on("keypress", "a", function (e) {
            if (e.which === 13) {
                $(this).click();
            }
        });

        if (_curScopeNode.get("type") === ScopeNodeType.Topic && _curScopeNode.get("props").leaf !== true) {
            _initTopicListLv2(_$topicLv2Panel);
        }
    };

    _init();

    _this.unselectSubtopic = function () {
        var parentNode = _curScopeNode.get("parent");
        if (parentNode && parentNode.get("type") === ScopeNodeType.Topic) {
            _$topicLv2Panel.find("li").removeClass("selected");
            _changeTopic(_$topicLv1Panel.find("li.selected a"));
        }
    };

    _this.changeScope = function (scope) {
        if (scope === _curScopeNode) {
            return; // no changed
        }

        if (scope instanceof ScopeNode) {
            var path = scope.getPath();
            if (path === _curProductNode.getPath()) {
                _this.reset();  //back to product === reset topic panel
            } else if (path === _curScopeNode.get("parent").getPath()) {
                _this.unselectSubtopic();   // back to topic level 1
            }
        }
    };

    _this.reset = function () {
        if (_topicLv2Panel) {
            _topicLv2Panel.getUpdatePanel().html('');
        }
        _$topicLv1Panel.find("li").removeClass("selected");
        _changeTopic();
    };

    _this.getScopeNode = function () {
        return _curScopeNode;
    };
};

Microsoft.Support.GSS.GPS.SolutionControl = function (selector, args) {
    // using
    var ScopeNodeType = Microsoft.Support.GSS.ScopeNodeType;
    var ScopeNode = Microsoft.Support.GSS.ScopeNode;

    var _this = this;
    var _$this = $(this);
    var _$panel = $(selector);
    var _defaultOptions = {
        serviceUrl: '/GuidedProblemSolving/GuidedProblemSolvingService.svc',
        language: 'en-us',
        scope: null,
        ajaxSettings: {
            cache: false,
            dataType: 'json'
        }
    };
    var _opts = $.extend(true, {}, _defaultOptions, args);
    var _currScope = _opts.scope instanceof ScopeNode ? _opts.scope : null;
    var _currPageNo = 1;
    var _totalPageCount = 1;
    var _totalHits = '';
    var _pagedHtmls = [];
    var _$prevPagingLink = $();
    var _$nextPagingLink = $();
    var _$pagingLinks = $();
    _this.superclass(_$panel, {
        loaded: true,
        ajaxSettings: $.extend(true, {}, _opts.ajaxSettings, {
            url: _opts.serviceUrl + "/GetSolutions",
            data: { lang: _opts.language }
        })
    });

    var _changePage = function (pageNo) {
        pageNo = parseInt(pageNo, 10);
        if (pageNo > 0) {
            _currPageNo = pageNo;
            if (_currPageNo === 1) {
                _$prevPagingLink.addClass("disabled");
            } else {
                _$prevPagingLink.removeClass("disabled");
            }

            if (_currPageNo === _totalPageCount) {
                _$nextPagingLink.addClass("disabled");
            } else {
                _$nextPagingLink.removeClass("disabled");
            }

            var $list = _pagedHtmls[pageNo.toString()];
            if ($list instanceof jQuery) {
                $(".solution-list", _$panel).children().detach().end().append($list);
                _$pagingLinks.removeClass("current-page").filter("[data-page-no='" + pageNo + "']").addClass("current-page");
                // update back/forward link href
                var baseHref = _$nextPagingLink.attr("href");
                if (baseHref) {
                    baseHref = baseHref.substr(0, baseHref.lastIndexOf("?"));
                    // set data-lts-href for lts logging, because href will be changed below.
                    _$nextPagingLink.add(_$prevPagingLink).each(function () {
                        $(this).data("lts-href", $(this).attr("href"));
                    });
                    _$nextPagingLink.filter(":not(.disabled)").attr("href", baseHref + "?page=" + (pageNo + 1));
                    _$prevPagingLink.filter(":not(.disabled)").attr("href", baseHref + "?page=" + (pageNo - 1));
                }
            } else {
                _this.load();
            }
            return true;
        }
        return false;
    };

    var _initContent = function (panel) {
        panel = panel || _$panel;

        // read params
        _totalHits = $("[data-total-hints]", panel).data("total-hints");
        _totalPageCount = parseInt($("[data-page-count]", panel).data("page-count"), 10);

        // init topic back link
        $(".topic-levels a.change-scope-link", panel).click(function (e) {
            var node = null;
            e.preventDefault();
            switch (parseInt($(this).data("scope-level"), 10)) {
                case 0:
                    node = _currScope.findParentByType(ScopeNodeType.Product, true);
                    break;
                case 1:
                    node = _currScope.get("parent");
                    break;
            }
            if (node) {
            _$this.trigger("scopechange", [node]);
            } else {
                return false;
            }
        });

        // init paged list
        _pagedHtmls = [];
        $("script[type='text/html'][data-page-no]", panel).each(function () {
            var $this = $(this);
            _pagedHtmls[$this.data("page-no").toString()] = $($this.html());
            $this.remove();
        });

        $("ul[data-page-no]", panel).each(function () {
            var $this = $(this);
            _pagedHtmls[$this.data("page-no").toString()] = $this;
        });

        // init pager
        $("a.page-link script[type='text/html']", panel).each(function () {
            var $this = $(this);
            $this.after($this.html()).remove();
        });

        _$pagingLinks = $("a.page-link[data-page-no]", panel).click(function (e) {
            e.preventDefault();
            _changePage($(this).data("page-no"));
        });

        // get current page no from pager
        _currPageNo = parseInt(_$pagingLinks.filter(".current-page").data("page-no"), 10);

        _$nextPagingLink = $("a.page-link.next-page", panel).click(function (e) {
            e.preventDefault();
            if ($(this).hasClass("disabled") === false) {
                _changePage(_currPageNo + 1);
            } else {
                e.stopPropagation();
            }
        });

        _$prevPagingLink = $("a.page-link.prev-page", panel).click(function (e) {
            e.preventDefault();
            if ($(this).hasClass("disabled") === false) {
                _changePage(_currPageNo - 1);
            } else {
                e.stopPropagation();
            }
        });

        // change to current page no content(specially for first load)
        _changePage(_currPageNo);
    };

    var _init = function () {
        _$panel.on("click", ".retry-link", null, function (e) {
            e.preventDefault();
            _this.load();
        });

        _$this.bind("beforeload", function (e, settings) {
            settings.data.path = _currScope.getPath();
            settings.data.pageNo = _currPageNo;
            settings.data.totalHitsList = _totalHits;
        }).bind("load", function (e, panel) {
            _initContent(panel);
        });

        _$panel.on("keypress", "a", function (e) {
            if (e.which === 13) {
                $(this).click();
            }
        });

        _initContent();
    };

    _init();

    _this.reset = function (scope) {
        _changePage(1);
    };

    _this.changeScope = function (scope) {
        if (scope instanceof ScopeNode) {
            if (_currScope !== scope) {
                _currScope = scope;
                _currPageNo = 1;    // turn to first page when resetted scope.
                _totalHits = '';
                _this.load();
            }
        }
    };
};
Microsoft.Support.GSS.GPS.SolutionControl.prototype.superclass = Microsoft.Support.GSS.AjaxUpdatePanel;

Microsoft.Support.GSS.GPS.LTS = function (statsDotNet, args) {
    // using
    var ScopeNodeType = Microsoft.Support.GSS.ScopeNodeType;
    var ScopeNode = Microsoft.Support.GSS.ScopeNode;

    var _this = this;
    var _$this = $(this);
    statsDotNet = statsDotNet || window.StatsDotNet || {};
    var _defaultOptions = {
        serviceUrl: statsDotNet.host,
        scope: null,
        debugMode: false,   // if you want to debug lts, you can set this value to: 'alert', 'console' or 'alert,console'
        debugFilter: function (msg) {
            return msg.substr(0, 5) === "[Log]";
        }
    };
    var _opts = $.extend({}, _defaultOptions, args);
    var _eventSeqNo = 0;
    var _ltsSender = new Microsoft.Support.LTSSender(_opts);
    var _scopeCounter = new Microsoft.Support.GSS.GPS.LTS.ScopeCounter(_opts.scope);

    var _fixedFields = {
        SSID: 25,
        URL: window.location,
        SiteCulture: statsDotNet.SiteCulture,
        ContentCulture: statsDotNet.ContentCulture,
        ContentID: statsDotNet.contentId,
        ContentType: statsDotNet.contentType
    };

    var _fixedFlexValues = {
        FlexID: 1
    };

    var _dynamicFields = {
        RequestDate: function () {
            return new Date().toDateString();
        },
        ActiveDwellTime: function () {
            return statsDotNet.activeDwellTime;
        },
        EventSeqNo: function () {
            return statsDotNet.eventSeqNo;
        }
    };

    var _getDynamicFields = function () {
        var fields = {};
        $.each(_dynamicFields, function (key, func) {
            fields[key] = func();
        });
        return fields;
    };

    var _getAllFields = function (flexValues) {
        return $.extend({}, _fixedFields, _getDynamicFields(), _fixedFlexValues, flexValues);
    };

    var _getCurrBrowserEvent = function () {
        if (window.event !== undefined) {
            return window.event;
        }

        var callStack = [];
        var func = arguments.callee.caller;
        while (func && $.inArray(func, callStack) === -1) {
            callStack.push(func);
            if (func.arguments[0] instanceof Event) {
                return func.arguments[0];
            }
            func = func.caller;
        }
        return null;
    };

    var _getCurrEvent = function (event) {
        event = event || _getCurrBrowserEvent();
        return event ? event.target ? event : $.event.fix(event) : null;
    };

    var _getEventType = function (eventType, modality, scope, query, extraParams) {
        extraParams = extraParams || {};
        var eventTypeFormat = _this.EventType[eventType] || eventType || '';
        return eventTypeFormat.replace(/\[[^\[\]]*\]/g, function (match) {
            var field = match.substr(1, match.length - 2);
            switch (field) {
                case "modality":
                    return modality;
                case "product":
                    var product = scope instanceof ScopeNode ? scope.findParentByType(ScopeNodeType.Product, true) : null;
                    return product instanceof ScopeNode ? product.get("key") : '';
                case "topic":
                    var topic = scope instanceof ScopeNode ? scope.findParentByType(ScopeNodeType.Topic, true) : null;
                    return topic instanceof ScopeNode ? topic.get("key") : '';
                case "scopeCounter":
                    if (eventTypeFormat === _this.EventType.GPSLink) {
                        _scopeCounter.addSACount();
                    } else {
                        _scopeCounter.changeScope(scope);
                    }
                    return _scopeCounter.toString();
                default:
                    if (extraParams[field] !== undefined) {
                        return extraParams[field];
                    }
                    return match;
            }
        });
    };

    var _getFlexValues = function (event, type, modality, scope, query, extraParams) {
        var $target = $((event || {}).target);
        var $link = $target.closest("a");
        type = type || $target.closest("[data-lts-event-type]").data("lts-event-type");
        return {
            FlexValue1: _eventSeqNo++,    //event no
            FlexValue2: _getEventType(type, modality, scope, query, extraParams),
            FlexValue3: $target.closest("[data-featureid]").data("featureid"),     //featureID
            FlexValue4: $link.data("lts-href") || $link.attr("href"),    //href
            FlexValue5: scope instanceof ScopeNode ? scope.getPath() : undefined,    //scope path
            FlexValue6: modality,    //modality
            FlexValue7: $.isPlainObject(query) ? $.param(query) : query,    //query
            FlexValue10: $.isPlainObject(extraParams) ? $.param(extraParams) : extraParams    //extras
        };
    };

    _this.log = function (type, modality, scope, query, extraParams, event) {
        var fields = _getAllFields(_getFlexValues(_getCurrEvent(event), type, modality, scope, query, extraParams));
        _ltsSender.send(fields);
    };
};

Microsoft.Support.GSS.GPS.LTS.prototype.EventType = {
    GPSInitStatus: 'GPSInitStatus',
    Search: 'Search_Product_[product]',
    Modality: 'Modality_[modality]',
    GPSProgram: 'GPSProgram_[scopeCounter]_[product]',
    GPSTopic1: 'GPSTopic1_[scopeCounter]_[topic]',
    GPSTopic2: 'GPSTopic2_[scopeCounter]_[topic]',
    GPSLink: 'GPSLink_[scopeCounter]',
    GPSShowTopic0: 'GPSShowTopic_[scopeCounter]',
    GPSShowTopic1: 'GPSShowSubtopic_[scopeCounter]',
    ClickForPagination: 'clickForPagination_[scopeCounter]',
    PSC: 'PSC_[scopeCounter]_[product]',
    ClickForCommunity: 'clickForCommunity'
};

Microsoft.Support.GSS.GPS.LTS.ScopeCounter = function (scope) {
    // using
    var ScopeNodeType = Microsoft.Support.GSS.ScopeNodeType;
    var ScopeNode = Microsoft.Support.GSS.ScopeNode;

    var _this = this;
    var _counter = [0, 0, 0, 0, 0];
    var _length = _counter.length;
    var _curScope = scope instanceof ScopeNode ? scope : null;

    var _addCount = function (idx) {
        if (idx >= 0) {
            _counter[idx] += 1;
        }
        _counter.splice(idx + 1, _counter.length - idx + 1);
        while (_counter.length < _length) {
            _counter.push(0);
        }
    };

    var _getScopePathNodes = function (scope) {
        var nodes = [];
        if (scope) {
            while (scope && scope.get("type") !== ScopeNodeType.Root) {
                nodes.push(scope);
                scope = scope.get("parent");
            }
        }
    };

    var _getScopeNodes = function (scope) {
        var nodeArray = [null, null, null, null];
        var productIdx = 0;
        var topicIdx = 2;
        $.each(scope.getPathNodes(true), function (idx, node) {
            switch (node.get("type")) {
                case ScopeNodeType.Product:
                    nodeArray[productIdx++] = node;
                    break;
                case ScopeNodeType.Topic:
                    nodeArray[topicIdx++] = node;
                    break;
            }
        });
        return nodeArray;
    };

    _this.addSACount = function () {
        _addCount(4);
    };

    _this.changeScope = function (scope) {
        scope = scope instanceof ScopeNode ? scope : null;
        if (scope) {
            var nodes = _getScopeNodes(scope);
            var matchIdx = -1;
            if (_curScope) {
                $.each(_getScopeNodes(_curScope), function (i, node) {
                    if ((nodes[i] === node) || (nodes[i] && node && nodes[i].get("key") === node.get("key"))) {
                        matchIdx = i;
                    } else {
                        return false;
                    }
                });
            }
            var i;
            for (i = matchIdx + 1; i < nodes.length; i++) {
                if (nodes[i]) {
                    _addCount(i);
                }
            }
        } else {
            _addCount(-1);
        }
        _curScope = scope;
    };

    _this.toString = function () {
        return _counter.join(".");
    };
};